package org.rainbowinverted.charging.device.connect.ykc.server.encoder;

import cn.hutool.core.util.HexUtil;
import org.rainbowinverted.charging.device.connect.ykc.server.constants.ChannelAttributeKeyConstants;
import org.rainbowinverted.charging.device.connect.ykc.server.constants.YkcConstants;
import org.rainbowinverted.charging.device.connect.ykc.server.handler.YkcAbstractHandler;
import org.rainbowinverted.charging.device.connect.ykc.server.message.out.YkcMessageOut;
import org.rainbowinverted.charging.device.connect.ykc.server.util.CrcChecksumUtil;
import org.rainbowinverted.charging.device.connect.ykc.server.util.YkcOpCodeHandlerMap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * 云快充编码器
 * @author hehuaiping
 */
@Slf4j
@Component
@AllArgsConstructor
@ChannelHandler.Sharable
public class YkcEncoder extends MessageToMessageEncoder<YkcMessageOut> {
    private final YkcOpCodeHandlerMap ykcOpCodeHandlerMap;
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, YkcMessageOut ykcMessageOut, List<Object> list) throws Exception {
        ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
        // 帧开始标志
        byteBuf.writeByte(YkcConstants.YKC_FRAME_START);
        // 数据长度
        byteBuf.writeByte(0x00);
        // 帧序列号
        byteBuf.writeShortLE(ykcMessageOut.getFrameSerialNo());
        // 加密标志
        byteBuf.writeByte(ykcMessageOut.getCryptoFlag() ? 0x01 : 0x00);
        // 帧类型
        Integer deviceCode = ykcOpCodeHandlerMap.convertToDeviceCode(ykcMessageOut.getMessageType());
        byteBuf.writeByte(deviceCode);
        // 数据域
        YkcAbstractHandler<?, YkcMessageOut> handler = ykcOpCodeHandlerMap.getHandler(ykcMessageOut.getMessageType());
        if (Objects.isNull(handler)) {
            log.error("message not matched handler: {}", ykcMessageOut);
            return;
        }
        handler.write(byteBuf, ykcMessageOut);
        // 计算数据长度，序列号域+加密标志+帧类型标志+消息体
        int dataLength = byteBuf.readableBytes() - 2;
        byteBuf.setByte(1, dataLength);
        // 帧校验，从序列号域到数据域的CRC校验
        byteBuf.readerIndex(2);
        byte[] data = new byte[dataLength];
        byteBuf.readBytes(data);
        int cryptoValue = CrcChecksumUtil.calculateCrc(data);
        byteBuf.writeBytes(HexUtil.decodeHex(String.format("%04x", cryptoValue)));
        // 十六进制消息
        byteBuf.resetReaderIndex();
        byte[] sendBytes = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(sendBytes);
        String dataHex = HexUtil.encodeHexStr(sendBytes);
        Long deviceNo = channelHandlerContext.channel().attr(ChannelAttributeKeyConstants.CHANNEL_ATTR_DEVICE_NO).get();
        // 因终端设备处理消息速度较慢，防止同一设备并发发送消息
        synchronized (deviceNo.toString().intern()) {
            log.info("send deviceNo: {}, frameType: {}, model hex: {}", deviceNo, String.format("%02x", deviceCode), dataHex);
            byteBuf.resetReaderIndex();
            list.add(byteBuf);
        }
    }
}
